#!/usr/bin/python

import itertools
import optparse
import pydot
import sets
import sys

def readprofiles(file):
  all = []

  for line in open(file):
    if line=="\n": continue
    if line[0]=="*": continue
    (acs0,profs0)=line.split("|")
    acs=acs0.replace(",s)",")").replace(" ","")
    profs=profs0.replace("],[","];[")
    actors=acs[1:-1].split(",")
    if profs != "[]\n":
      profiles=profs[1:-2].split(";")
    else:
      profiles=sets.Set()
    for profstr in profiles:
      profile = set(profstr[1:-1].split(","))
      all.append((actors,profile))

  return all

def coasubset(ac1, ac2):
  for a in ac1:
    if not(a in ac2) and not(a+'*' in ac2): return False
  return True

def ismincol(all,(ac1,prof1)):
  for (ac2,prof2) in all:
    if (ac2,prof2) != (ac1,prof1) and prof2 >= prof1 and coasubset(ac2,ac1): 
      return False
  return True

def arrow((acs,profs),(acs2,profs2)):
  return coasubset(acs,acs2) and sets.Set(profs) <= sets.Set(profs2)

def elimtable(all):
  elim = []
  for (ac1,prof1) in all:
    if ismincol(all,(ac1,prof1)):
      elim.append((len(elim),ac1,prof1))
  return elim

def sortnumberslast(x,y):
  if x == '' or y == '': return cmp(x,y)
  if x[0] in '0123456789' and not y[0] in '0123456789': return 1
  if y[0] in '0123456789' and not x[0] in '0123456789': return -1
  return cmp(x,y)
  

def stringrep(acs,profs):
  sprof = ""
  sac = ","

  acso = []
  for ac in acs:
#    if ac[-1]=='*': acso.append(ac[:-1])
#    else: acso.append(ac+'*')
    acso.append(ac)
  sac = ",".join(acso)

  sprofs = sorted(profs, cmp=sortnumberslast)
  sprofo = []
  for prof in sprofs:
		sprofo.append(prof)
  sprof = "".join(sprofo)

  return sac + "\\n" + sprof

def calcedges(nodelist):
  edges = []
  
  for (ix1,(acs1,profs1)) in enumerate(nodelist):
    for (ix2,(acs2,profs2)) in enumerate(nodelist):
      if ix1 != ix2 and arrow((acs1,profs1),(acs2,profs2)):
        edges.append((ix1,ix2))
  
  # take transitive reduction
  deledge = []
  for (ix1,(acs1,profs1)) in enumerate(nodelist):
    for (ix2,(acs2,profs2)) in enumerate(nodelist):
      for (ix3,(acs3,profs3)) in enumerate(nodelist):
        if (ix1,ix2) in edges and (ix2,ix3) in edges:
          deledge.append((ix1,ix3))
  
  for (ix1,ix2) in deledge:
    if (ix1,ix2) in edges: edges.remove((ix1,ix2))

  return edges


def implied(elim,(acs0,profs0)):
  for (ix,acs,profs) in elim:
    if coasubset(acs,acs0) and sets.Set(profs) >= sets.Set(profs0): return True
  return False

p = optparse.OptionParser()
p.add_option("--output","-o",action="store",dest="outfile", help="Output file: should end with .png; .svg also written")
#p.add_option("--full","-f",action="store_const",dest="exclude", const="", help="Use full profiles 123456789x, i.e., nothing excluded")
#p.add_option("--exclude","-e",action="store",dest="exclude", help="Exclude given items from profiles (default: 48x)")
#p.add_option("--actors","-a",action="store",dest="actors", help="Consider given actors (default: cpr123)")
#p.add_option("--merge-ci-ps","-m",action="store_const",const=True, dest="merge", help="Merge CI and PS actors (default: no)")
#p.add_option("--remember","-r",action="store_const",const=True, dest="remember", help="Consider only curious actors (default: no)")
p.set_defaults(outfile="graph.png")
opts,args = p.parse_args()

outfile = opts.outfile

all = []
elim = []

for file in args:
  z = readprofiles(file)
  all.append(z)
  elim.append(elimtable(z))

# node set
nodes = []
for elimi in elim:
  for (ix,acs,profs) in elimi:
    if len(profs) > 0 and not (acs,profs) in nodes: nodes.append((acs,profs))

graph = pydot.Dot(graph_type='digraph')
pynodes = {}

def style(ne,n):
  if ne==1: return 'solid'
  if ne==2: return ['dotted', 'dashed', 'solid'][n-1]
  if ne==3: return ['invisible', 'dashed', 'dotted', 'rounded', 'diagonals', 'bold, dashed', 'solid'][n-1]
  return 'solid'

#def style(n):
#  it = itertools.chain(['filled', 'dashed', 'dotted', 'dashed', 'dashed', 'filled', 'dotted', 'solid'], itertools.repeat('filled'))
#  return next(itertools.islice(it, n, None))

for (ix,(acs,profs)) in enumerate(nodes):
  if len(profs) > 0:
    pynodes[ix] = pydot.Node(stringrep(acs,profs))
    six = 0
    for elimi in elim:
      six = six*2 + (1 if implied(elimi,(acs,profs)) else 0)
#    if len(elim) == 1: six *= 3
    pynodes[ix].set('style', style(len(elim), six))
#    print six, style(len(elim), six), acs, profs
    graph.add_node(pynodes[ix])

edges = calcedges(nodes)

for (ix1,ix2) in edges:
  graph.add_edge(pydot.Edge(pynodes[ix1], pynodes[ix2]))

graph.write_png(outfile)
graph.write_svg(outfile.replace(".png",".svg"))
